module profiler_zrada_mod

  use datetime
  use string
  use container
  use flogger
  use params_mod
  use data_translators_utils_mod
  use profiler_mod

  implicit none

  private

  public profiler_zrada_read

contains

  subroutine profiler_zrada_read(file_path, stations, records, mute)

    character(*), intent(in) :: file_path
    type(hash_table_type), intent(inout) :: stations
    type(linked_list_type), intent(inout) :: records
    logical, intent(in), optional :: mute

    character(8) station_name
    integer ierr
    character(10) data_type
    character(2) device_type
    character(14) date_time_str
    character(100) line
    character(20) key
    integer h, k
    real lon, lat, z, ua, va, wa, wd, ws
    integer wnd_h_qc, wnd_v_qc
    type(datetime_type) time
    type(profiler_station_type), pointer :: station
    type(profiler_record_type), pointer :: record
    type(linked_list_iterator_type) record_iterator

    if (merge(.not. mute, .false., present(mute))) call log_notice('Reading ' // trim(file_path) // ' ...')
    open(101, file=file_path)
    read(101, '(A)', iostat=ierr) line
    if (ierr /= 0) then
      if (merge(.not. mute, .false., present(mute))) then
        print *, trim(line)
        call log_warning('Failed to read file ' // trim(file_path) // '!')
      end if
      return
    end if
    ! Skip junk characters if has.
    station_name = ''
    do
      read(101, '(A1)', advance='no') station_name(1:1)
      if (ichar(station_name(1:1)) /= 0) exit
    end do
    if (station_name(1:1) == '') then
      read(101, '(A5, X, F9.4, X, F8.4, X, F7.1, X, A2, X, A14)') station_name, lon, lat, z, device_type, date_time_str
    else
      read(101, '(A4, X, F9.4, X, F8.4, X, F7.1, X, A2, X, A14)') station_name(2:5), lon, lat, z, device_type, date_time_str
    end if
    call time%init(date_time_str, '%Y%m%d%H%M%S')
    read(101, *) data_type
    if (data_type(1:4) /= 'ROBS') then
      if (merge(.not. mute, .false., present(mute))) call log_warning('Currently, only ROBS wind profiler are supported!')
      return
    end if
    if (stations%hashed(station_name)) then
      select type (value => stations%value(station_name))
      type is (profiler_station_type)
        station => value
      end select
    else
      allocate(station)
      call station%init(station_name, lon, lat, z)
      call stations%insert(station_name, station)
    end if
    allocate(record)
    call record%init(alloc_hash=.true.)
    record%seq_id = records%size
    record%station => station
    record%time = time
    do while (.true.)
      read(101, '(A)') line
      if (line == 'NNNN') exit
      read(line(1:5), '(I5)') h
      if (line(7:12) == '//////' .or. line(14:19) == '//////') then
        wd = real_missing_value
        ws = real_missing_value
      else
        read(line( 7:12), '(F6.2)', iostat=ierr) wd
        if (ierr /= 0) wd = real_missing_value
        read(line(14:19), '(F6.2)', iostat=ierr) ws
        if (ierr /= 0) ws = real_missing_value
        read(line(28:30), '(I3)', iostat=ierr) wnd_h_qc
        if (ierr /= 0) wnd_h_qc = int_missing_value
      end if
      ua = wind_u_component(ws, wd)
      va = wind_v_component(ws, wd)
      if (line(21:26) == '//////') then
        wa = real_missing_value
      else
        read(line(21:26), '(F6.1)', iostat=ierr) wa
        if (ierr /= 0) wa = real_missing_value
        read(line(32:34), '(I3)', iostat=ierr) wnd_v_qc
        if (ierr /= 0) wnd_v_qc = int_missing_value
      end if
      key = to_str(h)
      if (.not. is_missing(h )) call record%pro_hash%h %insert(key, real(h))
      if (.not. is_missing(ua)) call record%pro_hash%ua%insert(key, ua)
      if (.not. is_missing(va)) call record%pro_hash%va%insert(key, va)
      if (.not. is_missing(wd)) call record%pro_hash%wd%insert(key, wd)
      if (.not. is_missing(ws)) call record%pro_hash%ws%insert(key, ws)
    end do
    close(101)

    call records%insert(station_name // '@' // time%isoformat(), record)

    ! Transfer read type to final type for easy use.
    record_iterator = linked_list_iterator(records)
    do while (.not. record_iterator%ended())
      select type (record => record_iterator%value)
      type is (profiler_record_type)
        if (associated(record%pro_hash)) then
          call record%pro%init(record%pro_hash%h%size)
          call record%pro%set_from_hash(record%pro_hash)
          call record%station%records%insert(record)
        end if
      end select
      call record_iterator%next()
    end do

    if (merge(.not. mute, .false., present(mute))) call log_notice('Station size is ' // trim(to_str(stations%size)) // ', record size is ' // trim(to_str(records%size)) // '.')

  end subroutine profiler_zrada_read

  subroutine profiler_zrada_read_files(file_paths, stations, records, mute)

    character(*), intent(in) :: file_paths
    type(hash_table_type), intent(inout) :: stations
    type(linked_list_type), intent(inout) :: records
    logical, intent(in), optional :: mute

    integer ierr, offset_s, offset_e
    character(255) file_path

    offset_s = 1
    do while (.true.)
      offset_e = index(file_paths(offset_s:len_trim(file_paths)), ',')
      if (offset_e /= 0) then
        file_path = file_paths(offset_s:offset_e-1)
      else
        file_path = file_paths(offset_s:len_trim(file_paths))
      end if
      call profiler_zrada_read(file_path, stations, records, mute)
    end do

  end subroutine profiler_zrada_read_files

end module profiler_zrada_mod
